package com.org.simpleMonopoly.shared;

import com.org.simpleMonopoly.shared.core.Board;
import com.org.simpleMonopoly.shared.core.Move;
import com.org.simpleMonopoly.shared.core.Player;
import com.org.simpleMonopoly.shared.core.Bank;
import com.org.simpleMonopoly.shared.core.Property;
import com.org.simpleMonopoly.shared.exceptions.IllegalMoveException;
import com.org.simpleMonopoly.shared.exceptions.IllegalPropertyActionException;
import com.org.simpleMonopoly.shared.exceptions.PlayerException;

public class Manager {
	
	private Board gameBoard  = null;
	private Player players[] = new Player[2];
	private Bank bank		 = null;
	private static int playerCount = 0;
	private int lastTurnPlayerIndex = 0;
	public static int getPlayerCount() {
		return playerCount;
	}

	public static void setPlayerCount(int playerCount) {
		Manager.playerCount = playerCount;
	}
	
	public Player[] getPlayers() {
		return players;
	}

	public void setPlayers(Player[] players) {
		this.players = players;
	}

	private void initializeBank(){
		this.bank = new Bank();
	}
	
	private void initializeGameBoard(){
		this.gameBoard = new Board(this.bank.getProperties());
	}
	
	
	public void init()
	{
		this.initializeBank();
		this.initializeGameBoard();
	}
	
	public void createPlayer(String firstName, String lastName) throws PlayerException{
		if(Manager.playerCount <= 1){
			players[Manager.playerCount] = new Player(firstName, lastName);
			Manager.playerCount++;
		}else{
			throw new PlayerException(PlayerException.MAX_PLAYER_LIMIT_EXCEPTION);
		}
	}
	
	public Board getGameBoard() {
		return gameBoard;
	}

	public void setGameBoard(Board gameBoard) {
		this.gameBoard = gameBoard;
	}

	public Bank getBank() {
		return bank;
	}

	public void setBank(Bank bank) {
		this.bank = bank;
	}

	public  int getLastTurnPlayerIndex() {
		return this.lastTurnPlayerIndex;
	}

	public  void setLastTurnPlayerIndex(int lastTurnPlayerIndex) {
		this.lastTurnPlayerIndex = lastTurnPlayerIndex;
	}
	
    public Move makeMove(int playerNumber, int numberOfMoves) throws IllegalMoveException{
    	//Check if the move is legal
		this.gameBoard.checkIfMoveIsValid(numberOfMoves, players[playerNumber].getPlayerId(), players[this.lastTurnPlayerIndex].getPlayerId());
		Move newMove = this.gameBoard.makeNewMove(this.players[playerNumber].getCurrentPosition(), numberOfMoves);
		this.players[playerNumber].setCurrentPosition(newMove.newPosition);
		//Now check if the move falls in a special case i.e. Income tax, Jail etc
		if(newMove.specialCellFlag){
			if(newMove.specialCellCode == this.gameBoard.getJAIL_POSITION_CODE()){
				this.players[playerNumber].setBalanceAmount(this.players[playerNumber].getBalanceAmount() - this.bank.getJAIL_PENALTY_AMOUNT());
			}else if(newMove.specialCellCode == this.gameBoard.getGO_TO_JAIL_POSITION_CODE()){
				this.players[playerNumber].setBalanceAmount(this.players[playerNumber].getBalanceAmount() - this.bank.getJAIL_PENALTY_AMOUNT());
			}else if(newMove.specialCellCode == this.gameBoard.getINCOME_TAX_POSITION_CODE()){
				this.players[playerNumber].setBalanceAmount(this.players[playerNumber].getBalanceAmount() - this.bank.getINCOME_TAX_PENALTY_AMOUNT());
			}
		}
		if(newMove.crossedStartPosition){
			this.players[playerNumber].setBalanceAmount(this.players[playerNumber].getBalanceAmount() + this.bank.getAUTO_CREDIT_AMOUNT());
		}
		//Now let's look for property
		if(!newMove.specialCellFlag && newMove.newPosition != this.gameBoard.getSTART_POSITION()){
			newMove = this.bank.getCurrentPropertyDetails(newMove, this.gameBoard.getPropertyIdByPosition(newMove.newPosition));
			if(!newMove.propertyAvailableForSaleFlag && newMove.propertyOwnedBy != this.players[playerNumber].getPlayerId()){
				int playerBalanceAfterPenalty = this.players[playerNumber].getBalanceAmount() - newMove.propertyPenalty;
				if(playerBalanceAfterPenalty < 0){
					//if insufficient funds then we can't do any thing
					newMove.insufficientFundFlag = true;
				} else{
					
					this.players[playerNumber].setBalanceAmount(playerBalanceAfterPenalty);
					for(int i = 0; i < this.players.length ; i++){
						if(this.players[i].getPlayerId() == newMove.propertyOwnedBy){
							this.players[i].setBalanceAmount(this.players[i].getBalanceAmount() + newMove.propertyPenalty);
							newMove.propertyOwnedBy = i;//just for making sure that we don't pass Id to the presenter
							break;
						}
					}
				}
				newMove.penaltyFlag = true;
			}
		}
		this.setLastTurnPlayerIndex(playerNumber);
		return newMove;
	}
	
	public void purchaseProperty(int playerNumber , int propertyBoardPosition) throws IllegalPropertyActionException
	{
		//First check if the cell is a special cell i.e. Jail, Start Position etc
		if(this.gameBoard.isSpecialCell(propertyBoardPosition) || propertyBoardPosition == this.gameBoard.getSTART_POSITION()){
			throw new IllegalPropertyActionException(IllegalPropertyActionException.SPECIAL_CELL_EXCEPTION);
		} else{
			//Now check if the property is available for Sale or Not
			int propertyId = this.gameBoard.getPropertyIdByPosition(propertyBoardPosition);
			if(propertyId == -1){
				throw new IllegalPropertyActionException(IllegalPropertyActionException.PROPERTY_DOESNOT_EXISTS_EXCEPTION);
			}
			if(this.bank.isPropertyAvailableForSale(propertyId)){
				Property tempProperty = this.bank.getPropertyById(propertyId);
				int userBalanceAfterPropertyPurchase = this.players[playerNumber].getBalanceAmount() - tempProperty.getPrice();
				if(userBalanceAfterPropertyPurchase < 0){
					throw new IllegalPropertyActionException(IllegalPropertyActionException.INSUFFICIENT_BALANCE_EXCEPTION); 
				}else{
					this.bank.commitPropertyPurchaseByUser(propertyId, this.players[playerNumber].getPlayerId());
					this.players[playerNumber].setBalanceAmount(userBalanceAfterPropertyPurchase);
				}
			}else{
				throw new IllegalPropertyActionException(IllegalPropertyActionException.PROPERTY_UNAVAILABLE_FOR_SALE_EXCEPTION);
			}
		}
	}
	
	public void sellProperty(int playerNumber , int propertyBoardPosition) throws IllegalPropertyActionException
	{
		//First check if the cell is a special cell i.e. Jail, Start Position etc
		if(this.gameBoard.isSpecialCell(propertyBoardPosition) || propertyBoardPosition == this.gameBoard.getSTART_POSITION()){
			throw new IllegalPropertyActionException(IllegalPropertyActionException.SPECIAL_CELL_EXCEPTION);
		} else{
			//Now check if the property exists or not
			int propertyId = this.gameBoard.getPropertyIdByPosition(propertyBoardPosition);
			if(propertyId == -1){
				throw new IllegalPropertyActionException(IllegalPropertyActionException.PROPERTY_DOESNOT_EXISTS_EXCEPTION);
			}
			//Now check whether the property is owned by someone or not
			if(!this.bank.isPropertyAvailableForSale(propertyId)){
				Property tempProperty = this.bank.getPropertyById(propertyId);
				if(tempProperty.getOwnedBy() == this.players[playerNumber].getPlayerId()){
					int userBalanceAfterPropertySale = this.players[playerNumber].getBalanceAmount() + tempProperty.getSellingPrice();
					this.bank.commitPropertySaleByUser(propertyId, this.players[playerNumber].getPlayerId());
					this.players[playerNumber].setBalanceAmount(userBalanceAfterPropertySale);
				}else{
					throw new IllegalPropertyActionException(IllegalPropertyActionException.USER_NOT_AUTHORIZED_EXCEPTION);
				}
			}else{
				throw new IllegalPropertyActionException(IllegalPropertyActionException.PROPERTY_UNAVAILABLE_FOR_SALE_EXCEPTION);
			}
		}
	}
}
